/******************************************************************************
*spartatorrent.c is a bit torrrent like file sharing program (Client SOftware) 
*Input: filename
*Output: File Seeding or Download.
*Author:Ashwin Raut , Aaditya Singhvi , Neeraj Naik , Aditya Kumar Verma
*Date:24th Nov 2010
*SpartaTorrent.All Rights Reserved (c) 2010 
*******************************************************************************/

#include "crc.h"
#include "header.h"
#include "dstruct.h"
#define BUFF 30
#define DEBUG
#define DEBUG_TEST_VALUES
/*Function to remove \r*/
 void rm_nline_char(char *in_string, int size)
 {
 	int j;
 	
 	for(j=0;j<size;j++){
 		if(in_string[j]=='\n'){
 			in_string[j]='\0';
 		}
 	}
 }
 
 
 
 void joinfile(char * filename,long int fileSize,int noOfParts,int lpsize)
{
	FILE *tempfp;
	FILE *fp;
	char newfilename[20];
	char appendedfile[20];
	char * buffer;
	size_t n;
	int i,Partno;
	sprintf(appendedfile,"%s%s","New",filename);
	fp=fopen(appendedfile,"a+");
	 buffer = (char*) malloc (sizeof(char)*PARTSIZE);
	 if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}
	printf("****Appending parts and forming: %s****\n",appendedfile);
	
#ifdef DEBUG
//	printf("received file size  %ldand parts %d and lpsizze%d****\n",fileSize,noOfParts,lpsize);
//	fflush(stdout);
#endif
	
	
	if(lpsize!=0){
	
		for(i=1;i<noOfParts;i++){
		memset(buffer,0,sizeof(buffer));
		sprintf(newfilename,"%s.part.%d",filename,i);
#ifdef DEBUG
//		printf("Appending %s to file %s\n",newfilename,appendedfile);
//		fflush(stdout);
#endif
		tempfp=fopen(newfilename,"r+");
		n=fread(buffer,1,PARTSIZE,tempfp);
		fwrite(buffer,1,n,fp);
		fclose(tempfp);
		}
		memset(buffer,0,sizeof(buffer));
		sprintf(newfilename,"%s.part.%d",filename,noOfParts);
#ifdef DEBUG
//		printf("Appending %s to file %s\n",newfilename,appendedfile);
//		fflush(stdout);
#endif
		tempfp=fopen(newfilename,"r+");
		n=fread(buffer,1,lpsize,tempfp);
		fwrite(buffer,1,lpsize,fp);
		fclose(tempfp);
		fclose(fp);
	}
	else{
	
		sprintf(newfilename,"%s.part.%d",filename,noOfParts);
#ifdef DEBUG
//		printf("Appending %s to file %s\n",newfilename,appendedfile);
//		fflush(stdout);
#endif
		tempfp=fopen(newfilename,"r+");
		n=fread(buffer,1,fileSize,tempfp);
		fwrite(buffer,1,fileSize,fp);
		fclose(tempfp);
		fclose(fp);
	
	
	}
free(buffer);

}

void delete_parts(char * filename,int noOfParts)
{
	int i;
	char newfilename[20];
	printf("no of parts = %d\n",noOfParts);
	for(i=1;i<=noOfParts;i++){
		sprintf(newfilename,"%s.part.%d",filename,i);
#ifdef DEBUG
//		printf("Deleting %s...\n",newfilename);
//		fflush(stdout);
#endif
		if(remove(newfilename) != 0)
			printf("Unable to delete %s\n",newfilename);
		else{
			;//printf("Deleted %s\n",newfilename);
		}
	}
}

 
 //FREE the linked LISt.
 
 
 
 
void create_list(struct file_part **headref,char * filename ,int pieces, int piecesize, int lpsize)
{

	struct file_part * new_node,*temp;
	int node_number=0;
	int no_of_nodes=0;
// For testing these values are hardcoded , normally they will be taken from tracker
	char testvalue_seederip[]="127.0.0.1";
	char testvalue_leecherip[]="192.168.1.69";
	unsigned int testvalue_seederport=SEEDERSERVERPORT;
	unsigned int testvalue_leecherport=7503;
//----
	for(node_number=1;node_number<=pieces;node_number++)
	{
		new_node= (struct file_part *) malloc(sizeof (struct file_part));
		
		// populate filename	
		strcpy(new_node->filename,filename);
		//sprintf(new_node->filename,"%s.part%d",filename,node_number);	
		// populate partnumber
		new_node->part_num= node_number;
		// populate part size
		if(node_number==pieces)
		{
			new_node->file_size=lpsize;
		}
		else
		{
			new_node->file_size=piecesize;
		}
		// initialize seeder list and leecehr list to zero.
		memset(&new_node->seeder_list,0,sizeof(new_node->seeder_list));
		memset(&new_node->leecher_list,0,sizeof(new_node->leecher_list));
	
#ifdef DEBUG_TEST_VALUES
		
		new_node->seeder_list[0].seeder_id=2000;
		inet_pton(AF_INET,testvalue_seederip, &(new_node->seeder_list[0].sd_sin.sin_addr));
		new_node->seeder_list[0].sd_sin.sin_port=htons(testvalue_seederport);
		
		new_node->leecher_list[0].leecher_id=1000;	
		inet_pton(AF_INET,testvalue_leecherip, &(new_node->leecher_list[0].lc_sin.sin_addr));
		new_node->leecher_list[0].lc_sin.sin_port=htons(testvalue_leecherport);
		
#endif	
		new_node->next=NULL;
		
		//set percent download
		new_node->percent_downloaded=00.00;


		if(*headref==NULL)
		{
			*headref=new_node;
			no_of_nodes++;
			
		}
		else
		{ // iterate to the end
			
			temp=*headref;
			while(temp->next!=NULL)
			{
				temp=temp->next;
				
			}
			temp->next=new_node;
			no_of_nodes++;
			
		
		}
	}



}

void print_list(struct file_part *temp)
{
	char pipbuff[BUFF]={0};
	int i=0;
	
	while(temp!=NULL){
		printf("\n***The Data in linked list is:***");
		printf("\nFilename: %s",temp->filename);
		printf("\nPart number: %d",temp->part_num);
		printf("\nPart Size: %d",temp->file_size);
		printf("\n Seeder Info:\n");
		for(i=0;i<MAX_SEEDS;i++)
		{
			//************************************* Change the formatting specifiers according to length
			printf("\tID:%5d", temp->seeder_list[i].seeder_id);
			inet_ntop(AF_INET, &(temp->seeder_list[i].sd_sin.sin_addr), pipbuff, BUFF);
			printf("  Seeder ip is :%16s",pipbuff);	
			memset(&pipbuff,0,BUFF);
			printf(" | ");
			if((i%3)==2){
			printf("\n");
			}
		}
		printf("\n Leecher Info:\n");
		for(i=0;i<MAX_LEECHES;i++)
		{
			printf("\tID:%5d", temp->leecher_list[i].leecher_id);
			inet_ntop(AF_INET, &(temp->leecher_list[i].lc_sin.sin_addr), pipbuff, BUFF);
			printf("  Leecher ip is :%16s",pipbuff);	
			memset(&pipbuff,0,BUFF);
			printf(" | ");
			if((i%3)==2){
			printf("\n");
			}
		}
		printf("\npercent download is: %f\n",temp->percent_downloaded);
		temp=temp->next;
		printf("*****************************************************\n");
	}
	
}


int manager(char * argument1)
{
	struct file_part *head=NULL;
	char filename[MAX_FILENAME_LEN]={0};
	char fname_argument[MAX_FILENAME_LEN]={0};
	char *extension;
	unsigned int extension_len=0,length,filename_len;	
	char *torrentextension=".storrent";
	crc filecrc;
	int2c crc_union;
	
	
	
	
	// Variables used to store the parsed data.
	FILE * fp_storrent;
	struct sockaddr_in trackersocketaddr;
	char filebuffer_storrent[100]={0};
	char filebuffer1_storrent[100]={0};
	unsigned int filesize_storrent=0;
	char trackerIP[BUFF];
	unsigned int trackerport;
	long int fileSize;
	int pieces,piecesize;
	int lpsize=0;
	crc filecrc_parsed;
	char * field,*fieldvalue;
	int node_number=0;
	
	trackersocketaddr.sin_family=AF_INET; // change this for IPV6.
	
		
		extension=strstr(argument1,torrentextension);
		strcpy(fname_argument,argument1);
		extension_len=strlen(extension);
		fflush(stdout);
		length=strlen(argument1);
		filename_len=length-extension_len;
		strncpy(filename,fname_argument,filename_len);
		printf("\n The filename parsed is :%s",filename);
	
	//PARSE THE .STORRENT FILE.
	fp_storrent = fopen(fname_argument , "r");
	if(fp_storrent==NULL)
	{
		printf("\n\n*************ERROR**************");
		printf("\nFile Not Present.\nPlease download *.storrent file in current folder\n");
		printf("*******************************\n");
		fflush(stdout);
		exit(1);
	}
	fseek(fp_storrent,0,SEEK_END);
	filesize_storrent=ftell(fp_storrent);
	rewind(fp_storrent);
	
		
	//File Parsing
	while(!feof(fp_storrent))
	{	
		fgets(filebuffer_storrent,100,fp_storrent);
		rm_nline_char(filebuffer_storrent,strlen(filebuffer_storrent));
		field=strtok(filebuffer_storrent," ");
		fieldvalue=strtok(NULL," ");
/*		printf("%s",field);
		printf("\n");
		printf("%s",fieldvalue);
		printf("\n");
*/
		if(!strcmp("TrackerIP",field))
		{
			//change this for IPv6
			inet_pton(AF_INET,fieldvalue, &(trackersocketaddr.sin_addr));
			inet_ntop(AF_INET, &(trackersocketaddr.sin_addr), trackerIP, BUFF);
#ifdef DEBUG
			printf("\nTracker ip is :%s",trackerIP);
#endif
		}
		else if (!strcmp("TrackerPort",field))
		{
			//change this for IPv6
			trackerport=atoi(fieldvalue);
			trackersocketaddr.sin_port=htons(trackerport);
#ifdef DEBUG		
			printf("\nTracker port number is :%d",trackerport);
#endif
		}
		else if (!strcmp("FileSize",field))
		{
			fileSize=atol(fieldvalue);
#ifdef DEBUG
			printf("\nFile size is :%ld",fileSize);
#endif			
		}
		else if (!strcmp("Pieces",field))
		{
				pieces=atoi(fieldvalue);
#ifdef DEBUG
				printf("\npieces :%d",pieces);
#endif
		}
		else if (!strcmp("PieceSize",field))
		{
			   piecesize=atoi(fieldvalue);
#ifdef DEBUG
			   printf("\npiecessize :%d",piecesize);
#endif
		}
		else if (!strcmp("LastPieceSize",field))
		{
				lpsize=atoi(fieldvalue);
#ifdef DEBUG
				printf("\nlpsize :%d",lpsize);
#endif
		}
		else if (!strcmp("Filecrc",field))
		{
	
			filecrc_parsed=atoi(fieldvalue);
#ifdef DEBUG			
			printf("\nfilecrc_parsed :%X",filecrc_parsed);
#endif
		}
	}
	//check if file is present or no and if present crc matches?
	if(fopen(filename,"r")==NULL)
	{
		printf("\nFile Not present, starting leecher and getting seeder info from tracker\n");
	}
	else
	{
		printf("\nFile present, checking crc ...%s",filename);
		filecrc=calculatecrc(filename);
		if(filecrc==filecrc_parsed)
		{
			printf("\nComplete File is present, updating tracker and starting seeder\n");
		}
	}
	
	create_list(&head,filename,pieces,piecesize,lpsize);
#ifdef DEBUG
	print_list(head);
#endif
	
	fclose(fp_storrent);
	for(node_number=1;node_number<=pieces;node_number++)
	{
		leecher_client(head,filename,node_number);
	}
#ifdef DEBUG
//	print_list(head);
#endif
	joinfile(filename,fileSize,pieces,lpsize);
	printf("******************************************************************************\n");
	fflush(stdout);
	delete_parts(filename,pieces);
	printf("******************************************************************************\n");
	fflush(stdout);
	return 0;
}



int main(int argc, char * argv[])
{

	
	printf("\n**Starting Program**");
	printf("\n the no of arguments is :%d",argc)	;
	
	if(argc!=2){
	printf("\n\n*************ERROR**************");
	printf("\nUSAGE: ./sparta [option]\n")	;
	printf("\t[option]: filename.extension.storrent\n")	;
	printf("Example: ./sparta photo.jpg.storrent\n")	;
	printf("*******************************\n");
	fflush(stdout);
	exit(1);
	}
	if(argc>0){
	manager(argv[1]);
	}
	
	return 0;
}

